package com.ruoyi.common.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.ruoyi.common.config.AliyunConfig;
import com.ruoyi.common.exception.ServiceException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 阿里云OSS工具类
 */
@Component
public class OssUtils {

    private static AliyunConfig aliyunConfig;

    @Autowired
    private AliyunConfig aliyunConfigAutowired;

    @PostConstruct
    public void init() {
        aliyunConfig = aliyunConfigAutowired;
    }

    /**
     * 获取OSS客户端实例
     */
    private static OSS getOssClient() {
        return new OSSClientBuilder().build(
                aliyunConfig.getOssEndpoint(),
                aliyunConfig.getOssAccessKeyId(),
                aliyunConfig.getOssAccessKeySecret());
    }

    /**
     * 上传文件到OSS
     *
     * @param file     文件对象
     * @param filePath 文件路径（不包含文件名）
     * @return 文件访问URL
     */
    public static String upload(MultipartFile file, String filePath) {
        if (file == null || file.isEmpty()) {
            throw new ServiceException("上传文件不能为空");
        }

        // 获取原始文件名
        String originalFilename = file.getOriginalFilename();
        // 生成新的文件名（防止重名）
        String fileName = generateFileName(originalFilename);
        // 构建完整的文件路径
        String fullPath = buildFullPath(filePath, fileName);

        OSS ossClient = getOssClient();
        try {
            // 创建上传请求
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    aliyunConfig.getOssBucketName(),
                    fullPath,
                    file.getInputStream());

            // 上传文件
            ossClient.putObject(putObjectRequest);

            // 返回文件访问URL
            return getFileUrl(fullPath);
        } catch (IOException e) {
            throw new ServiceException("文件上传失败：" + e.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 上传文件到OSS
     *
     * @param inputStream 文件流
     * @param filePath    文件路径（不包含文件名）
     * @param fileName    文件名
     * @return 文件访问URL
     */
    public static String upload(InputStream inputStream, String filePath, String fileName) {
        if (inputStream == null) {
            throw new ServiceException("文件流不能为空");
        }

        // 构建完整的文件路径
        String fullPath = buildFullPath(filePath, fileName);

        OSS ossClient = getOssClient();
        try {
            // 创建上传请求
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    aliyunConfig.getOssBucketName(),
                    fullPath,
                    inputStream);

            // 上传文件
            ossClient.putObject(putObjectRequest);

            // 返回文件访问URL
            return getFileUrl(fullPath);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 从OSS下载文件
     *
     * @param filePath 文件路径（包含文件名）
     * @return 文件字节数组
     */
    public static byte[] download(String filePath) {
        OSS ossClient = getOssClient();
        try {
            // 判断文件是否存在
            if (!ossClient.doesObjectExist(aliyunConfig.getOssBucketName(), filePath)) {
                throw new ServiceException("文件不存在");
            }

            // 获取文件
            OSSObject ossObject = ossClient.getObject(aliyunConfig.getOssBucketName(), filePath);
            try (InputStream inputStream = ossObject.getObjectContent()) {
                return IOUtils.toByteArray(inputStream);
            }
        } catch (IOException e) {
            throw new ServiceException("文件上传失败：" + e.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 删除OSS上的文件
     *
     * @param filePath 文件路径（包含文件名）
     */
    public static void delete(String filePath) {
        OSS ossClient = getOssClient();
        try {
            // 判断文件是否存在
            if (!ossClient.doesObjectExist(aliyunConfig.getOssBucketName(), filePath)) {
                return;
            }

            // 删除文件
            ossClient.deleteObject(aliyunConfig.getOssBucketName(), filePath);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 批量删除OSS上的文件
     *
     * @param filePaths 文件路径列表（包含文件名）
     */
    public static void batchDelete(List<String> filePaths) {
        if (filePaths == null || filePaths.isEmpty()) {
            return;
        }

        OSS ossClient = getOssClient();
        try {
            // 构建删除请求
            DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(aliyunConfig.getOssBucketName())
                    .withKeys(filePaths);

            // 批量删除文件
            ossClient.deleteObjects(deleteObjectsRequest);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 获取文件访问URL
     *
     * @param filePath 文件路径（包含文件名）
     * @return 文件访问URL
     */
    public static String getFileUrl(String filePath) {
        if (StringUtils.isBlank(filePath)) {
            return null;
        }

        OSS ossClient = getOssClient();
        try {
            // 设置URL过期时间（10年）
            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
            URL url = ossClient.generatePresignedUrl(aliyunConfig.getOssBucketName(), filePath, expiration);
            if (url != null) {
                // 替换为CDN域名（如果有配置）
                if (StringUtils.isNotBlank(aliyunConfig.getOssCdnDomain())) {
                    return url.toString().replace(
                            aliyunConfig.getOssBucketName() + "." + aliyunConfig.getOssEndpoint(),
                            aliyunConfig.getOssCdnDomain());
                }
                return url.toString();
            }
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 生成唯一的文件名
     *
     * @param originalFilename 原始文件名
     * @return 新文件名
     */
    private static String generateFileName(String originalFilename) {
        String prefix = "";
        String suffix = "";

        if (StringUtils.isNotBlank(originalFilename)) {
            int lastDotIndex = originalFilename.lastIndexOf(".");
            if (lastDotIndex != -1) {
                // 提取原文件名（不含扩展名）和扩展名
                prefix = originalFilename.substring(0, lastDotIndex) + "_";
                suffix = originalFilename.substring(lastDotIndex);
            } else {
                // 如果没有扩展名，整个原始文件名作为前缀
                prefix = originalFilename + "_";
            }
        }

        // 生成UUID并去除连字符，与原始文件名组合
        return prefix + UUID.randomUUID().toString().replace("-", "") + suffix;
    }
    /**
     * 构建完整的文件路径
     *
     * @param filePath 文件路径（不包含文件名）
     * @param fileName 文件名
     * @return 完整的文件路径
     */
    private static String buildFullPath(String filePath, String fileName) {
        if (StringUtils.isBlank(filePath)) {
            return fileName;
        }

        // 去除路径前后的斜杠
        filePath = StringUtils.strip(filePath, "/");

        return filePath + "/" + fileName;
    }
}
